﻿using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApp1;

internal class Program
{
    // 以代理的形式使用函数指针
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int FuncDelegate(int arg);

    /* 导入dll,声明里面的函数 */
    // add函数,带有函数指针
    [DllImport(@"F:\Practice\C++\CppExportCFunc\cpp\cmake-build-release\bin\MyCLib.dll",
        CallingConvention = CallingConvention.Cdecl)]
    public static extern int add(int arg, IntPtr func);

    // 字符串函数
    [DllImport(@"F:\Practice\C++\CppExportCFunc\cpp\cmake-build-release\bin\MyCLib.dll",
        CallingConvention = CallingConvention.Cdecl)]
    public static extern int theStr(string arg);

    // 使用字符串数组
    [DllImport(@"F:\Practice\C++\CppExportCFunc\cpp\cmake-build-release\bin\MyCLib.dll",
        CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr theStrArr([In] [Out] string[] arg, int size);
    
    // 返回字符串
    [DllImport(@"F:\Practice\C++\CppExportCFunc\cpp\cmake-build-release\bin\MyCLib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void returnStr(string arg, StringBuilder buffer, int bufferSize);

    // 测试用的函数指针
    private static int MyAdd(int num)
    {
        return num + 100;
    }

    private static void Main(string[] args)
    {
        // 以代理的形式使用
        FuncDelegate del = MyAdd;
        var p = Marshal.GetFunctionPointerForDelegate(del);

        var r = add(10, p);
        Console.WriteLine($"the value:{r}");

        var s = "aabc";
        var size = theStr(s);
        Console.WriteLine($"the str size:{size}");

        /* 测试字符串数组 */
        string[] arg = {"one", "two", "three"};
        var resultPtr = theStrArr(arg, arg.Length);
        // Manually marshal the IntPtr to string array
        string[] results = null;
        if (resultPtr != IntPtr.Zero)
        {
            results = new string[arg.Length];
            for (var i = 0; i < arg.Length; i++)
            {
                var strPtr = Marshal.ReadIntPtr(resultPtr, i * IntPtr.Size);
                results[i] = Marshal.PtrToStringAnsi(strPtr);
            }
        }

        foreach (var item in results)
        {
            Console.WriteLine(item);
        }
        
        /* 测试返回字符串 */
        StringBuilder buffer = new StringBuilder(256);
        returnStr("Hello, World!", buffer, buffer.Capacity);
        Console.WriteLine(buffer.ToString());
    }
}